package com.zslc.securitymonitoring.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.zslc.securitymonitoring.dao.*;
import com.zslc.securitymonitoring.entity.Region;
import com.zslc.securitymonitoring.enums.AlermSeverityEnum;
import com.zslc.securitymonitoring.enums.AlermStatusEnum;
import com.zslc.securitymonitoring.enums.AlermTypeEnum;
import com.zslc.securitymonitoring.service.AlarmTypeService;
import com.zslc.securitymonitoring.vo.GlobalSeverityStatistic;
import com.zslc.securitymonitoring.vo.RegionStatistic;
import com.zslc.securitymonitoring.vo.UrlStatistic;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Service
public class AlarmTypeServiceImpl implements AlarmTypeService {
    @Autowired
    private AvailabilityMapper availabilityMapper;
    @Autowired
    private PhishingMapper phishingMapper;
    @Autowired
    private SpamlinkMapper spamlinkMapper;
    @Autowired
    private TrojanMapper trojanMapper;
    @Autowired
    private VulMapper vulMapper;
    @Autowired
    private AlarmTypeMapper alarmTypeMapper;
    @Autowired
    private RegionMapper regionMapper;

    @Qualifier("asyncDataExecutor")
    @Autowired
    private TaskExecutor taskExecutor;

    @Override
    public Map<String, List<GlobalSeverityStatistic>> severityStatisticBy6Month() throws ExecutionException, InterruptedException {
        Map<String, List<GlobalSeverityStatistic>> resultMap = new TreeMap<>();
        //异步执行5个独立的查库操作
        CompletableFuture<List<GlobalSeverityStatistic>> avaCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return availabilityMapper.severityStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<List<GlobalSeverityStatistic>> phishCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return phishingMapper.severityStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<List<GlobalSeverityStatistic>> spamlinkCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return spamlinkMapper.severityStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<List<GlobalSeverityStatistic>> trojanCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return trojanMapper.severityStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<List<GlobalSeverityStatistic>> vulCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return vulMapper.severityStatisticBy6Month();
        }, taskExecutor);
        List<GlobalSeverityStatistic> avalList = avaCompletableFuture.get();
        List<GlobalSeverityStatistic> phisList = phishCompletableFuture.get();
        List<GlobalSeverityStatistic> spamList = spamlinkCompletableFuture.get();
        List<GlobalSeverityStatistic> trojList = trojanCompletableFuture.get();
        List<GlobalSeverityStatistic> vulList = vulCompletableFuture.get();
        avalList.addAll(phisList);
        avalList.addAll(spamList);
        avalList.addAll(trojList);
        avalList.addAll(vulList);
        Map<String, List<GlobalSeverityStatistic>> yearmonthMap = avalList.parallelStream().collect(Collectors.groupingBy(GlobalSeverityStatistic::getYearMonth));
        List<String> lastSixMonths = getLastSixMonths();
        for (String month : lastSixMonths) {
            List<GlobalSeverityStatistic> resultList = new ArrayList<>(4);

            List<GlobalSeverityStatistic> statistics = yearmonthMap.get(month);
            if (CollectionUtil.isNotEmpty(statistics)) {
                for (AlermSeverityEnum severityEnum : AlermSeverityEnum.values()) {
                    Integer sumNum = statistics.parallelStream().filter(s -> StringUtils.equals(s.getSeverity(), severityEnum.getValue())).collect(Collectors.summingInt(GlobalSeverityStatistic::getNum));

                    GlobalSeverityStatistic resultEntity = new GlobalSeverityStatistic();
                    resultEntity.setYearMonth(month);
                    resultEntity.setSeverity(severityEnum.getValue());
                    resultEntity.setNum(sumNum);
                    resultList.add(resultEntity);
                }
            }
            resultMap.put(month, resultList);
        }
        return resultMap;
    }

    @Override
    public List<Map<String, Object>> typeStatisticBy6Month() throws ExecutionException, InterruptedException {
        List<Map<String, Object>> resultList = new ArrayList<>();

        //异步执行5个独立的查库操作
        CompletableFuture<Integer> avaCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return availabilityMapper.typeStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<Integer> phishCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return phishingMapper.typeStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<Integer> spamlinkCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return spamlinkMapper.typeStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<Integer> trojanCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return trojanMapper.typeStatisticBy6Month();
        }, taskExecutor);
        CompletableFuture<Integer> vulCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return vulMapper.typeStatisticBy6Month();
        }, taskExecutor);
        Integer avalNum = avaCompletableFuture.get();
        Integer phisNum = phishCompletableFuture.get();
        Integer spamNum = spamlinkCompletableFuture.get();
        Integer trojNum = trojanCompletableFuture.get();
        Integer vulNum = vulCompletableFuture.get();
        Integer sumNum = avalNum + phisNum + spamNum + trojNum + vulNum;

        for (AlermTypeEnum typeEnum : AlermTypeEnum.values()) {
            Map<String, Object> resultMap = new HashMap<>();
            String formattedPercentage = "";
            switch (typeEnum.getValue()) {
                case "availability": {
                    resultMap.put("num", avalNum);
                    // 计算百分比
                    double percentage = ((double) avalNum / sumNum) * 100;
                    // 保留两位小数
                    formattedPercentage = String.format("%.2f%%", percentage);
                    break;
                }
                case "spamlink": {
                    resultMap.put("num", spamNum);
                    // 计算百分比
                    double percentage = ((double) spamNum / sumNum) * 100;
                    // 保留两位小数
                    formattedPercentage = String.format("%.2f%%", percentage);
                    break;
                }
                case "phishing": {
                    resultMap.put("num", phisNum);
                    // 计算百分比
                    double percentage = ((double) phisNum / sumNum) * 100;
                    // 保留两位小数
                    formattedPercentage = String.format("%.2f%%", percentage);
                    break;
                }
                case "trojan": {
                    resultMap.put("num", trojNum);
                    // 计算百分比
                    double percentage = ((double) trojNum / sumNum) * 100;
                    // 保留两位小数
                    formattedPercentage = String.format("%.2f%%", percentage);
                    break;
                }
                case "vul": {
                    resultMap.put("num", vulNum);
                    // 计算百分比
                    double percentage = ((double) vulNum / sumNum) * 100;
                    // 保留两位小数
                    formattedPercentage = String.format("%.2f%%", percentage);
                    break;
                }
                default: {
                    break;
                }
            }

            resultMap.put("type", typeEnum.getValue());
            resultMap.put("percent", formattedPercentage);
            resultList.add(resultMap);
        }
        return resultList;
    }

    @Override
    public List<UrlStatistic> urlStatisticBy30Day() {
        List<UrlStatistic> list = alarmTypeMapper.urlStatisticBy30Day();
        return list;
    }

    @Override
    public List<RegionStatistic> regionStatistic() throws ExecutionException, InterruptedException {
        List<RegionStatistic> resultList = new ArrayList<>();
        //异步执行5个独立的查库操作
        CompletableFuture<List<RegionStatistic>> avaCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return availabilityMapper.regionStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> phishCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return phishingMapper.regionStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> spamlinkCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return spamlinkMapper.regionStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> trojanCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return trojanMapper.regionStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> vulCompletableFuture = CompletableFuture.supplyAsync(() -> {
            return vulMapper.regionStatistic();
        }, taskExecutor);
        CompletableFuture<List<Region>> regionCompletableFuture = CompletableFuture.supplyAsync(() -> {
            Region region = new Region();
            region.setParentCode("0");
            return regionMapper.selectListByObj(region);
        }, taskExecutor);

        //异步查询地区告警类型数量统计数据
        CompletableFuture<List<RegionStatistic>> availabilityFuture = CompletableFuture.supplyAsync(() -> {
            return availabilityMapper.regionTypeNumStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> phishingFuture = CompletableFuture.supplyAsync(() -> {
            return phishingMapper.regionTypeNumStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> spamlinkFuture = CompletableFuture.supplyAsync(() -> {
            return spamlinkMapper.regionTypeNumStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> trojanFuture = CompletableFuture.supplyAsync(() -> {
            return trojanMapper.regionTypeNumStatistic();
        }, taskExecutor);
        CompletableFuture<List<RegionStatistic>> vulFuture = CompletableFuture.supplyAsync(() -> {
            return vulMapper.regionTypeNumStatistic();
        }, taskExecutor);

        List<RegionStatistic> avaList = avaCompletableFuture.get();
        List<RegionStatistic> phisList = phishCompletableFuture.get();
        List<RegionStatistic> spamList = spamlinkCompletableFuture.get();
        List<RegionStatistic> trojList = trojanCompletableFuture.get();
        List<RegionStatistic> vulList = vulCompletableFuture.get();

        List<RegionStatistic> avaTypeNumList = availabilityFuture.get();
        List<RegionStatistic> phisTypeNumList = phishingFuture.get();
        List<RegionStatistic> spamTypeNumList = spamlinkFuture.get();
        List<RegionStatistic> trojTypeNumList = trojanFuture.get();
        List<RegionStatistic> vulTypeNumList = vulFuture.get();

        List<Region> regionList = regionCompletableFuture.get();
        for (Region region1 : regionList) {
            RegionStatistic regionStatistic = new RegionStatistic();
            regionStatistic.setCode(region1.getCode());
            regionStatistic.setName(region1.getName());
            regionStatistic.setLng(region1.getLng());
            regionStatistic.setLat(region1.getLat());

            List<RegionStatistic> avaList1 = avaList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> phisList1 = phisList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> spamList1 = spamList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> trojList1 = trojList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> vulList1 = vulList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            avaList1.addAll(phisList1);
            avaList1.addAll(spamList1);
            avaList1.addAll(trojList1);
            avaList1.addAll(vulList1);
            if (CollectionUtil.isEmpty(avaList1)) {
                //都为空，说明该省级没有告警信息
                continue;
            }
            Optional<RegionStatistic> newMatch = avaList1.parallelStream().filter(a -> StringUtils.equals(a.getStatus(), AlermStatusEnum.NEW.getValue()))
                    .findAny();
            if (!newMatch.isPresent()) {
                regionStatistic.setStatus("noNew");
            } else {
                regionStatistic.setStatus(AlermStatusEnum.NEW.getValue());
            }

            //赋值数据中的最高威胁等级
            List<RegionStatistic> avaList0 = avaTypeNumList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> phisList0 = phisTypeNumList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> spamList0 = spamTypeNumList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> trojList0 = trojTypeNumList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            List<RegionStatistic> vulList0 = vulTypeNumList.parallelStream().filter(a -> StringUtils.equals(a.getCode(), region1.getCode())).collect(Collectors.toList());
            avaList0.addAll(phisList0);
            avaList0.addAll(spamList0);
            avaList0.addAll(trojList0);
            avaList0.addAll(vulList0);

            //统计高中低三种级别漏洞
            String seversity = "low";
            List<Map<String, Object>> list = new ArrayList<>();
            for (AlermSeverityEnum severityEnum : AlermSeverityEnum.values()) {
                Map<String, Object> tempMap = new HashMap<>(3);
                tempMap.put("severity", severityEnum.getValue());
                Map<String, List<RegionStatistic>> typeMap = avaList0.parallelStream().filter(a -> StringUtils.equals(a.getSeverity(), severityEnum.getValue())).collect(Collectors.groupingBy(RegionStatistic::getType));
                if (CollectionUtil.isEmpty(typeMap)) {
                    continue;
                }
                List<Map<String, Object>> lowTypeNumMap = getTypeNumMap(typeMap);
                tempMap.put("data", lowTypeNumMap);
                list.add(tempMap);

                if(StringUtils.equals("middle",severityEnum.getValue()) && StringUtils.equals("low",seversity)){
                    seversity = severityEnum.getValue();
                }else if (StringUtils.equals("high", severityEnum.getValue())) {
                    seversity = severityEnum.getValue();
                }
            }
            regionStatistic.setSeverity(seversity);
            regionStatistic.setList(list);

            resultList.add(regionStatistic);
        }
        return resultList;
    }

    private List<Map<String, Object>> getTypeNumMap(Map<String, List<RegionStatistic>> typeMap) {
        List<Map<String, Object>> typeStatisticList = new ArrayList<>();
        typeMap.keySet().forEach(t -> {
            Map<String, Object> typeStatisticMap = new HashMap<>();
            for (AlermTypeEnum value : AlermTypeEnum.values()) {
                if (StringUtils.equals(t, value.getValue())) {
                    typeStatisticMap.put("type", value.getMsg());
                }
            }
            Integer size = typeMap.get(t).parallelStream().collect(Collectors.summingInt(RegionStatistic::getCount));
            typeStatisticMap.put("count", size);
            typeStatisticList.add(typeStatisticMap);
        });
        return typeStatisticList;
    }


    private static List<String> getLastSixMonths() {
        List<String> months = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        // 获取当前日期
        LocalDate now = LocalDate.now();
        // 循环6次，获取最近6个月的年月
        for (int i = 0; i < 6; i++) {
            months.add(now.minusMonths(i).format(formatter));
        }
        // 如果需要按照时间顺序排序（最近的月份在列表前面），可以反转列表
//        Collections.reverse(months);
        return months;
    }
}
